
/* 

 	Declare Class CMD/Constructor - Meaning AjaxLab.Cmd = function is both
		a class declaration, as well as contructor method. 
		
	The default parameter eventhough is not shown passed in, but it's there 
		by default. It's called 'arguments' which is an array object. 
		
	Because it's a class, we can declar private variables, public properties. 
		for example, var copyright is my private variable
					 this.getCopyRight is my public property. 
	
	Because it's a construtor as well,  I can also call any method when get instantiated. 
		for example
*/
Type.registerNamespace("AjaxLab.Engine.Abstract");




AjaxLab.Engine.Abstract.Cmd= function(CommandPromptContainer, CommandPromptTextArea, DebugArea, CommandPromptRoot)
{
				
			this.charactercount                     =   0;
	
			this.commandListernerStack              =   new Object();
			this.documentationListnerStack          =   new Object();
			this.plugInCommandsQueue				=	new Object();
			
			this.enableAutoComplete					=	false;
			
			/* Declare private class variables */
			var promptSeparator						=	":\\>";
			var commandpromptID                     =   "CommandPrompt";
            var commandPrompt                       =    $(commandpromptID);
			var copyright                           =   "AjaxLab Web Command Prompt 1.0 (LGPL) \n" +
														 "<C> CopyRighted 2006 AjaxLab.com \n";
			var root								=	"/";
			
			var isDebug                             =   false;
			var debug;
			var debug_area							=	"debugZone";
  		 	var instance                            =   this;
			
			/* 
				Call My Own "Constructor" so to speak 
				The reason I commented out "instance.PreLoad(arguments)* below
				is because it seems the javascript is executed sequentially 
				where the order of the function matters. 
				
				In PreLoad(), it calls "setCommandPrompt()", but here, it's not
				yet available. 
			*/
			
				//instance.PreLoad(arguments);
			
			/* 
				Private Functions 
				
				Can Call
					
					-	Public Properties by specify instance.*
					- 	Public Functions by specify instance.*
					- 	Extended Functions	by specify instance.*
					-	Private properties and private fucntions directly
					
				Why are they private? how are they different from the public class properties above? 
				Notice these function don't have this.* = in front of them. The object instantied
					this class wont' be able to access these class. Tha'ts why they are private
			
			*/
            
			function Trim(myString)
            {   
                return  Trim_Trailing_LineFeed_Helper(myString);
            }
			
            function Trim_Trailing_LineFeed_Helper(s)
            {
                if(s!=null)
                {
                    while( (s.charCodeAt(s.length-1) == 10) || (s.charCodeAt(s.length-1) == 13) )
                    {
                        s = s.substring(0,s.length-1);
                    }
                }
                return s;
            }

            function Trim_Trailing_LineFeed(element){
                var s = element.value;  
                s = Trim_Trailing_LineFeed_Helper(s);
                element.value=s;
            }
    
            function scrollElementToEnd(element){
                if (typeof element.scrollTop != 'undefined' &&
                   typeof element.scrollHeight != 'undefined') {
                 element.scrollTop = element.scrollHeight;
               }
            }
	
	    	function rePosition()
			{
                var content = instance.getCommandPrompt();
                Trim_Trailing_LineFeed(content);
                scrollElementToEnd(content);
            }
			
			function GetMouseCoords(e)
			{
				e = (e) ? e : window.event;
				
				var x = 0;
				var y = 0;
				
				if(e.pageX)
				{
					x = e.pageX;
					y = e.pageY;
				}
				
				else if(e.clientX)
				{
					x = e.clientX + document.body.scrollLeft;
					y = e.clientY + document.body.scrollTop;
				}
				
				instance.Debug(" x : "+x + " y:"+y);
				instance.Debug("page x:"+e.pageX + "y:"+e.pageY);
			}

	  		function setKeyDownEvent(e)
			{
				instance.Debug("key down 1");
				instance.Debug("page x:"+e.pageX + "y:"+e.pageY);
				
                var characterCode
                var text                    = instance.getCommandPrompt();
				//var commandListernerStack   = instance.getRegisterCommandListener();
				
							var myField         =   instance.getCommandPrompt();
							if(myField!=null)
							{
								if (document.selection) {
									instance.Debug("enter detected. Create range");
									myField.focus();
									sel = document.selection.createRange();
									
									if(instance.enableAutoComplete==true)
									{
										var myc = document.getElementById("Cmd");
										var startx = myc.style.left
										var starty = myc.style.top;
										instance.Debug("command prompt left : "+startx + " top :"+starty);
									
										var eventx = e.clientX;
										var eventy = e.clientY;
										instance.Debug("key client x:" + eventx + " y:"+eventy);
										
										var tRect=sel.getBoundingClientRect(); 
										var top = tRect.top
										var left = tRect.left;
										instance.Debug("top :"+top+" left:"+left);
										
										var div = document.getElementById("myDiv");							
										div.style.display="block";
										div.style.top = top;
										div.style.left = left+7;
									}

								}
								else if(window.getSelection)
								{
									
									if(instance.enableAutoComplete==true)
									{
										var startPos = myField.selectionStart;
										var endPos = myField.selectionEnd;
										instance.Debug("start position x:"+startPos+" end post x:"+endPos);
										
										var eventx = e.pageX;
										var eventy = e.pageY;
										instance.Debug("key client x:" + eventx + " y:"+eventy);
											
										var myc = document.getElementById("Cmd");
										var startx = myc.style.left
										var starty = myc.style.top;
										var startxnum = startx.split("px")[0];
										var startynum = starty.split("px")[0];
										instance.Debug("command prompt left : "+startxnum+ " top :"+startynum);
										
										startx = parseInt(startxnum)+240+(instance.charactercount)*8+"px";
										starty = parseInt(startynum)+100+"px";
										instance.Debug("new x :"+startx);
										var div = document.getElementById("myDiv");							
										div.style.display="block";
										div.style.top = starty;
										div.style.left = startx;
									}
								
								}
								else if (myField.selectionStart || myField.selectionStart == '0') {
									instance.Debug("FireFox 2 ");
									var startPos = myField.selectionStart;
									var endPos = myField.selectionEnd;
									
									var myc = document.getElementById("Cmd");
									var startx = myc.style.left
									var starty = myc.style.top;
									instance.Debug("command prompt left : "+startx + " top :"+starty);
									
									var tRect=sel.getBoundingClientRect(); 
									var top = tRect.top
									var left = tRect.left;
									instance.Debug("top :"+top+" left:"+left);
									
								} else {
									
								}
							}
							
				 
                if(e && e.which)
                { 
                    characterCode = e.which 
                }
                else if(document.getElementById)
                {
                     characterCode = e.keyCode
                }
                else{
                    characterCode = event.keyCode 
                }
                //alert(characterCode);
                if(characterCode!=13 && characterCode!=8 && characterCode!=38)  //As long as it's not a backspace or carriage return.
                {   
                   instance.charactercount++; 
                }
                else if (characterCode ==8){
                     instance.charactercount--; 
                     if (instance.charactercount < 0)
                     {
                        text.value = text.value+">";
                        instance.charactercount = 0;
                     }
                }
                else if(characterCode==38){ //upper arrow key left:37 right:39 down:40
                    text.value=text.value;
                }
                else if(characterCode == 13) //If carriage return is pressed.
                {   
                    var commandstring = Trim(text.value);
                    var inputtext   = commandstring.substring(commandstring.length-instance.charactercount); 
                    var command     = inputtext.split(" ");
					instance.Debug(command[0]);
   					if(instance.commandListernerStack==null)
					{
						instance.Debug("CommandListnerStack is null");
					}
					else{
						instance.Debug("CommandListnerStack is not null");
						/*
							if(AjaxLab.Engine.Interface.ICommand.isImplementedBy(CommandObject))
							{
								this.ProcessCommands = Function.apply();
								
								CommandObject.ProccessCommands();
							}
						*/
						var basecommands = new AjaxLab.Engine.Plugins.BaseCommands();
						var myDelegate = basecommands.returnCommandsDelegate();
						var s = myDelegate("test");
						instance.Debug(s);
						var customCommands= basecommands.getCommands();
						instance.Debug("Custom Commans:"+customCommands);
						
						if(inputtext=="")
						{
							instance.newPrompt();
						}
						else if(command[0].toUpperCase() == "CLEAR" || command[0].toUpperCase() == "CLS")
						{
							instance.Debug("Clear detected");
							if(command[1]==null)
							{
								instance.clearScreen();
							}
							else if(command[1].toUpperCase() == "DEBUG")
							{
								instance.Debug("Clear Debug detected");
								instance.emptyDebugZone();
							}
						}
						else if(command[0].toUpperCase()=="ENABLE")
						{
							instance.Debug("Enable detected");
							if(command[1].toUpperCase() == "AUTOCOMPLETE")
							{
								instance.Debug("auto complete on");

								instance.enableAutoComplete = true;
								instance.newPrompt();
							}
						}
						else if(command[0].toUpperCase()=="DISABLE")
						{
							instance.Debug("Disaable detected");
							if(command[1].toUpperCase() == "AUTOCOMPLETE")
							{
								instance.Debug("auto complete off");
								instance.enableAutoComplete = false;
								var div = document.getElementById("myDiv");							
								div.style.display="none";
								instance.newPrompt();
							}
						}
						else if(command[0].toUpperCase()=="CD")
						{
							if(command[1]!="")
							{
								instance.cd(command[1]);
							}
						}
						else if(instance.commandListernerStack[command[0]]!=null)
						{
							//this.commandListernerStack[command[0]](text,command[0],inputtext); //Call the appropriate function associated with the command
							
						}
						else{
							instance.Debug("No Command Found");
							instance.printToConsole(inputtext+" is not recognized as an internal or external command");
						}
						
					}
                    instance.charactercount=0;
                }
            }
        
            function setKeyUpEvent(e)
			{
 			   instance.Debug("key up");
               if(e && e.which)
                { 
                    e = e
                    characterCode = e.which 
                }
                else{
                    e = event
                    characterCode = e.keyCode 
                }
                if(characterCode == 13)
                {   
                	//instance.newPrompt();
					rePosition();
                }
            }
			
			/* Public Properties */
			
			this.getPromptSeparator = function()
			{
				return promptSeparator;
			}
			
			this.getCopyRight = function()
			{
				return copyright;
			}
			
			this.setIsDebug = function (isdebugParam)
			{
				isDebug = isdebugParam;
			}
			
			this.getIsDebug = function()
			{
				return isDebug;
			}
			
			this.setDebugZone								=	function(debugZone)
			{
				debug_area		=	debugZone;
			}
			
			this.getDebugZone								=	function()
			{
				return $(debug_area);
			}
			
			this.setCommandPromptID                         =    function(commandPromptIDParam)
            {
                commandpromptID =   commandPromptIDParam;
            }
    
            this.getCommandPromptID                         =    function()
            {
                return commandpromptID;
            }

			this.setCommandPrompt                         =    function(commandPromptIDParam)
            {
                commandpromptID =   commandPromptIDParam;
            }
			
            this.getCommandPrompt                           =    function()
            {
                return $(commandpromptID);
            }

            this.setCopyright                               =    function(copyrightParam)
            {
                copyright = copyrightParam;
            }
            this.getCopyright                               =    function(){
                return copyright;
            }

            this.setRoot                                    =    function(rootParam){
                root    =   rootParam;
            }

            this.getRoot                                    =    function(){
                return root;
            }
			
			/* 
				Protected Function 
				1) Are these public functions just like prototype.* public funtions? Inherited class can
					access these fucntions only or prototyp.* public functions as well?
				2) In this case, what's the difference between public function and public properties?
				3) The reaosn I created this is because prototype.insertLibIntoHeadSection() try to call
					this method. if it were a private function (without this.* = ), it won't recongize it
				4) Now that it's public, it servers teh same purpose as protpty.insertLibIntoheaderSectin(),
					is this necesary? or when inherited class comes in, it makes a difference?
			*/
			this.Debug 				=	function Debug(value)
            {
                if(isDebug)
                {
					if(debug==null) 
					{
						debug 	=	new AjaxLab.Log4J();
					}
	
                    instance.getDebugZone().innerHTML = value+"<br/>"+instance.getDebugZone().innerHTML;
                }
            }
			
			
			/* 
				Insert a single library after the current library
				Note, if called seperately, then it's a stack in hierachy. 
				First one in, last one in the hierachy
				For example
				
					1) insert lib1		cmd.js
									   	lib1.js
										
					2) insert lib2		cmd.js
										lib2.js
										lib1.js
			*/
			this.insertDefaultLibrary=	function (library)
			{
				var script_tag = document.getElementsByTagName("head")[0].getElementsByTagName("script");
				for(var i=0;i<script_tag.length;i++)
				{
					var current_element = script_tag[i];
					var src = current_element.getAttribute("src");
					if(src!=null)
					{
						if(src.lastIndexOf("CMD")>0)
						{
							var import_script = document.createElement("script");
							import_script.setAttribute("src", library, 0);
							import_script.setAttribute("type", "text/javascript", 0);
							import_script.setAttribute("language", "JavaScript", 0);
							current_element.parentNode.insertBefore(import_script,current_element.nextSibling);
							break;
						}
					}
				}
			}	
			
			/* 
				Insert an array of libraries after the current library. 
				Unlike singular insertDefaultLibrary, this will keep the hierachy of the array
				Act as a queue. 
				
				For example, 
				
					  var CommandsLibrary=new Array(
									"ScriptLibrary/AjaxLabCommandPrompt/Log/Log4J.js",
									"ScriptLibrary/AjaxLabCommandPrompt/UI/AtlasExtend/DragAndDrop/DropZoneBehavior.js",
									"ScriptLibrary/AjaxLabCommandPrompt/Util/common.js"
									);
					  the hierachy will have the EXACT order.  
			*/
			
			this.insertDefaultLibraries=	function (CommandsLibrary)
			{
				 if(CommandsLibrary!=null)
				 {
					  var x; 
					  for(x=CommandsLibrary.length-1; x>=0;x--)
					  {
						
						var script_tag = document.getElementsByTagName("head")[0].getElementsByTagName("script");
						for(var i=0;i<script_tag.length;i++)
						{
							var current_element = script_tag[i];
							var src = current_element.getAttribute("src");
							if(src!=null)
							{
								if(src.lastIndexOf("Core/CMD")>0)
								{
									var import_script = document.createElement("script");
									import_script.setAttribute("src", CommandsLibrary[x], 0);
									import_script.setAttribute("type", "text/javascript", 0);
									import_script.setAttribute("language", "JavaScript", 0);
									current_element.parentNode.insertBefore(import_script,current_element.nextSibling);
									break;
								}
							}
						}
					  }
				 }
			}	
			
			
			this.importLibrary								=	function(library)
			{
				var script_tag = document.getElementsByTagName("head")[0].getElementsByTagName("script");
				for(var i=0;i<script_tag.length;i++)
				{
					var current_element = script_tag[i];
					var src = current_element.getAttribute("src");
					if(src!=null)
					{
						if(src.lastIndexOf("CMD")>0)
						{
							var import_script = document.createElement("script");
							import_script.setAttribute("src", library, 0);
							import_script.setAttribute("type", "text/javascript", 0);
							import_script.setAttribute("language", "JavaScript", 0);
							current_element.parentNode.insertBefore(import_script,current_element);
							break;
						}
					}
				}
			}
			
			this.importLibraries					=	function (CommandPromptLibrary)
			{
				 if(CommandPromptLibrary!=null)
				 {
					  var x; 
					  for(x=0; x<CommandPromptLibrary.length;x++)
					  {
						
						var script_tag = document.getElementsByTagName("head")[0].getElementsByTagName("script");
						for(var i=script_tag.length-1;i>=0;i--)
						{
							var current_element = script_tag[i];
							var src = current_element.getAttribute("src");
							if(src!=null)
							{
								if(src.lastIndexOf("Core/CMD")>0)
								{
									var import_script = document.createElement("script");
									import_script.setAttribute("src", CommandPromptLibrary[x], 0);
									import_script.setAttribute("type", "text/javascript", 0);
									import_script.setAttribute("language", "JavaScript", 0);
									current_element.parentNode.insertBefore(import_script,current_element);
									break;
								}
							}
						}
					  }
				 }
			}
			

            this.addDefautlKeyListener                      =      function(){
                if (navigator.userAgent.indexOf("Safari") > 0) {
                    instance.getCommandPrompt().addEventListener("keydown", setKeyDownEvent,false);
                    instance.getCommandPrompt().addEventListener("keyup",setKeyUpEvent,false);
                } else if (navigator.product == "Gecko") {
                    instance.getCommandPrompt().addEventListener("keypress",setKeyDownEvent,false);
                    instance.getCommandPrompt().addEventListener("keyup",setKeyUpEvent,false);  
                } else {
					instance.Debug("attachEvent");
                    instance.getCommandPrompt().attachEvent('onkeydown',setKeyDownEvent);
                    instance.getCommandPrompt().attachEvent('onkeyup',setKeyUpEvent);
                }
            }
			
			this.InitPlugIns								=	Function.abstractMethod;
			instance.registerDefaultLibraries(CommandPromptContainer, CommandPromptTextArea, DebugArea, CommandPromptRoot);
}

AjaxLab.Engine.Abstract.Cmd.registerAbstractClass('AjaxLab.Engine.Abstract.Cmd');


//AjaxLab.Engine.Abstract.Cmd.registerAbstractClass('AjaxLab.Engine.Abstract.Cmd', AjaxLab.Engine.Interface.ICommands);

/* 

	Below are the EXTENDED public function. Similar to an inherited function. 
	
	It has access and 
	
		Can call 
	
			- public properties
			- protected functions
			
		Can NOT call
		
			- private functions

*/




AjaxLab.Engine.Abstract.Cmd.prototype = {
	
		/* Accepts an array object */
		registerDefaultLibraries		:	function(CommandPromptContainer, CommandPromptTextArea, DebugArea, CommandPromptRoot)
		{
				  var scriptLoader = new Sys.ScriptLoader();
				  var startHandler = Function.createDelegate(this, this.onPreLoad);
				  var scripts = [
								   	'ScriptLibrary/AjaxLabCommandPrompt/Engine/Interface/ICommands.js',
									'ScriptLibrary/AjaxLabCommandPrompt/Engine/Abstract/Commands.js',
									'ScriptLibrary/AjaxLabCommandPrompt/Util/CmdUtil.js',
									'ScriptLibrary/AjaxLabCommandPrompt/Log/Log4J.js',
									'ScriptLibrary/AjaxLabCommandPrompt/UI/AtlasExtend/DragAndDrop/DropZoneBehavior.js',
									'ScriptLibrary/AjaxLabCommandPrompt/Util/common.js'
								 ];
				  var scriptcontext = [
									   CommandPromptContainer,
									   CommandPromptTextArea,
									   DebugArea,
									   CommandPromptRoot
									  ]
				  scriptLoader.load(scripts, startHandler,scriptcontext);
		},
		
	 	onPreLoad							:	function(context)
		{
				this.setCommandPrompt(context[1]);
				this.setDebugZone(context[2]);
				this.setRoot(context[3]);
				this.clearScreen();
                this.addDefautlKeyListener();								
				this.InitPlugIns();
		},
		
		registerCommandsPlugin:	function(ScriptPath,ClassName)
		{
		
			if(ScriptPath!=null)
			{
				var scriptLoader = new Sys.ScriptLoader();
				var startHandler = Function.createDelegate(this, this.onRegisterPlugin);
				var scripts = [ScriptPath];
				scriptLoader.load(scripts, startHandler, ClassName);
			}
		}, 
		
		onRegisterPlugin:	function(ClassName)
		{
			alert("got registered "+ClassName);		
			var tempclass = ClassName;
			var mytype = Type.parse(tempclass);
			var tempobject = new mytype();
			alert(tempobject.getCommands());	
		},
		
		emptyScreen					:	 function()
		{
				this.getCommandPrompt().value = "";
		},
		
		clearScreen					: 	 function()
		{
				this.emptyScreen();
				this.print(this.getCopyright());
                this.println();
                this.print(this.getRoot());
                this.print(this.getPromptSeparator());
		},
		
		emptyDebugZone				:	function()
		{
				this.getDebugZone().innerHTML = "";
				this.println();
				this.print(this.getRoot());
				this.print(this.getPromptSeparator());
		},
		
	  	appendToConsole:            function (myValue){
            
            var myField         =   this.getCommandPrompt();
            if(myField!=null)
            {
                if (document.selection) {
                    myField.focus();
                    sel = document.selection.createRange();
                    sel.text = myValue;
                }
                else if (myField.selectionStart || myField.selectionStart == '0') {
                    var startPos = myField.selectionStart;
                    var endPos = myField.selectionEnd;
                    myField.value = myField.value.substring(0, startPos)+ myValue+ myField.value.substring(endPos, myField.value.length);
                } else {
                    myField.value += myValue;
                }
            }
        },  
           
        cd    :                     function(valueParam)
        {
            this.setRoot(valueParam);
			this.newPrompt();
        },
 
        print :                     function(valueParam)
		{
            this.appendToConsole(valueParam);
        }, 

		println:					function(valueParam)
		{
			var value = "";
			if(valueParam!=null)
			{
				value = valueParam;
			}
			value = value+"\n";
			this.appendToConsole(value);
		}, 
	
		printToConsole:             function(valueParam){
			this.println();
            this.println(valueParam);
			this.println();
            this.print(this.getRoot()+this.getPromptSeparator());
        },
		
		newPrompt:					function()
		{
				var text = this.getCommandPrompt().value;
				
				text = text + "\n"+this.getRoot()+":\\>";
				this.getCommandPrompt().value = text;
				this.charactercount=0;
		},
		
		insertLibIntoHeadSection  		:    function (CommandsLibrary)
		{	
			 if(CommandsLibrary!=null)
			 {
				 this.insertDefaultLibraries(CommandsLibrary);
			 }
		},
		
        setRegisterCommandListener:     function(CommandNames, commandListenerFunction, commandDocumentationFunction){
                var commandarray = CommandNames.split("|");
                var x = 0;
                for (x=0; x<commandarray.length;x++)
                {
                   this.commandListernerStack[commandarray[x].toUpperCase()]= commandListenerFunction;
                   this.documentationListnerStack[commandarray[x].toUpperCase()]= commandDocumentationFunction;
                }
        },
            
        getRegisterCommandListener:     function(){
                return this.commandListernerStack;
        }
}